package com.kexio.common.util;

import java.time.DayOfWeek;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Date;

/**
 * 日期时间工具类
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
public class DateTimeUtils {
    
    /**
     * 默认日期格式
     */
    public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd";
    
    /**
     * 默认日期时间格式
     */
    public static final String DEFAULT_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
    
    /**
     * ISO日期时间格式
     */
    public static final String ISO_DATETIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss";
    
    /**
     * 时间格式
     */
    public static final String TIME_PATTERN = "HH:mm:ss";
    
    /**
     * 紧凑日期时间格式
     */
    public static final String COMPACT_DATETIME_PATTERN = "yyyyMMddHHmmss";
    
    // 常用格式化器
    public static final DateTimeFormatter DEFAULT_DATE_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_DATE_PATTERN);
    public static final DateTimeFormatter DEFAULT_DATETIME_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_DATETIME_PATTERN);
    public static final DateTimeFormatter ISO_DATETIME_FORMATTER = DateTimeFormatter.ofPattern(ISO_DATETIME_PATTERN);
    public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern(TIME_PATTERN);
    public static final DateTimeFormatter COMPACT_DATETIME_FORMATTER = DateTimeFormatter.ofPattern(COMPACT_DATETIME_PATTERN);
    
    private DateTimeUtils() {
        // 工具类不允许实例化
    }
    
    // ==================== 获取当前时间 ====================
    
    /**
     * 获取当前日期
     */
    public static LocalDate now() {
        return LocalDate.now();
    }
    
    /**
     * 获取当前日期时间
     */
    public static LocalDateTime nowDateTime() {
        return LocalDateTime.now();
    }
    
    /**
     * 获取当前时间
     */
    public static LocalTime nowTime() {
        return LocalTime.now();
    }
    
    /**
     * 获取当前时间戳(毫秒)
     */
    public static long currentTimeMillis() {
        return System.currentTimeMillis();
    }
    
    /**
     * 获取当前时间戳(秒)
     */
    public static long currentTimeSeconds() {
        return System.currentTimeMillis() / 1000;
    }
    
    // ==================== 格式化 ====================
    
    /**
     * 格式化日期 (yyyy-MM-dd)
     */
    public static String formatDate(LocalDate date) {
        return date == null ? null : date.format(DEFAULT_DATE_FORMATTER);
    }
    
    /**
     * 格式化日期时间 (yyyy-MM-dd HH:mm:ss)
     */
    public static String formatDateTime(LocalDateTime dateTime) {
        return dateTime == null ? null : dateTime.format(DEFAULT_DATETIME_FORMATTER);
    }
    
    /**
     * 格式化时间 (HH:mm:ss)
     */
    public static String formatTime(LocalTime time) {
        return time == null ? null : time.format(TIME_FORMATTER);
    }
    
    /**
     * 自定义格式化
     */
    public static String format(LocalDateTime dateTime, String pattern) {
        return dateTime == null ? null : dateTime.format(DateTimeFormatter.ofPattern(pattern));
    }
    
    /**
     * 自定义格式化
     */
    public static String format(LocalDate date, String pattern) {
        return date == null ? null : date.format(DateTimeFormatter.ofPattern(pattern));
    }
    
    // ==================== 解析 ====================
    
    /**
     * 解析日期字符串 (yyyy-MM-dd)
     */
    public static LocalDate parseDate(String dateStr) {
        if (dateStr == null || dateStr.trim().isEmpty()) {
            return null;
        }
        try {
            return LocalDate.parse(dateStr, DEFAULT_DATE_FORMATTER);
        } catch (DateTimeParseException e) {
            throw new IllegalArgumentException("无法解析日期字符串: " + dateStr, e);
        }
    }
    
    /**
     * 解析日期时间字符串 (yyyy-MM-dd HH:mm:ss)
     */
    public static LocalDateTime parseDateTime(String dateTimeStr) {
        if (dateTimeStr == null || dateTimeStr.trim().isEmpty()) {
            return null;
        }
        try {
            return LocalDateTime.parse(dateTimeStr, DEFAULT_DATETIME_FORMATTER);
        } catch (DateTimeParseException e) {
            throw new IllegalArgumentException("无法解析日期时间字符串: " + dateTimeStr, e);
        }
    }
    
    /**
     * 解析时间字符串 (HH:mm:ss)
     */
    public static LocalTime parseTime(String timeStr) {
        if (timeStr == null || timeStr.trim().isEmpty()) {
            return null;
        }
        try {
            return LocalTime.parse(timeStr, TIME_FORMATTER);
        } catch (DateTimeParseException e) {
            throw new IllegalArgumentException("无法解析时间字符串: " + timeStr, e);
        }
    }
    
    /**
     * 自定义格式解析
     */
    public static LocalDateTime parseDateTime(String dateTimeStr, String pattern) {
        if (dateTimeStr == null || dateTimeStr.trim().isEmpty()) {
            return null;
        }
        try {
            return LocalDateTime.parse(dateTimeStr, DateTimeFormatter.ofPattern(pattern));
        } catch (DateTimeParseException e) {
            throw new IllegalArgumentException("无法解析日期时间字符串: " + dateTimeStr, e);
        }
    }
    
    // ==================== 转换 ====================
    
    /**
     * LocalDateTime转时间戳(毫秒)
     */
    public static long toTimestamp(LocalDateTime dateTime) {
        return dateTime == null ? 0 : dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }
    
    /**
     * 时间戳(毫秒)转LocalDateTime
     */
    public static LocalDateTime fromTimestamp(long timestamp) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault());
    }
    
    /**
     * Date转LocalDateTime
     */
    public static LocalDateTime fromDate(Date date) {
        return date == null ? null : date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
    }
    
    /**
     * LocalDateTime转Date
     */
    public static Date toDate(LocalDateTime dateTime) {
        return dateTime == null ? null : Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());
    }
    
    // ==================== 计算 ====================
    
    /**
     * 计算两个日期之间的天数差
     */
    public static long daysBetween(LocalDate start, LocalDate end) {
        return Duration.between(start.atStartOfDay(), end.atStartOfDay()).toDays();
    }
    
    /**
     * 计算两个时间之间的小时差
     */
    public static long hoursBetween(LocalDateTime start, LocalDateTime end) {
        return Duration.between(start, end).toHours();
    }
    
    /**
     * 计算两个时间之间的分钟差
     */
    public static long minutesBetween(LocalDateTime start, LocalDateTime end) {
        return Duration.between(start, end).toMinutes();
    }
    
    /**
     * 计算两个时间之间的秒差
     */
    public static long secondsBetween(LocalDateTime start, LocalDateTime end) {
        return Duration.between(start, end).getSeconds();
    }
    
    // ==================== 判断 ====================
    
    /**
     * 判断是否为今天
     */
    public static boolean isToday(LocalDate date) {
        return date != null && date.equals(LocalDate.now());
    }
    
    /**
     * 判断是否为今天
     */
    public static boolean isToday(LocalDateTime dateTime) {
        return dateTime != null && dateTime.toLocalDate().equals(LocalDate.now());
    }
    
    /**
     * 判断是否为工作日 (周一到周五)
     */
    public static boolean isWorkday(LocalDate date) {
        if (date == null) {
            return false;
        }
        DayOfWeek dayOfWeek = date.getDayOfWeek();
        return dayOfWeek.getValue() >= 1 && dayOfWeek.getValue() <= 5;
    }
    
    /**
     * 判断是否为周末
     */
    public static boolean isWeekend(LocalDate date) {
        if (date == null) {
            return false;
        }
        DayOfWeek dayOfWeek = date.getDayOfWeek();
        return dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY;
    }
    
    // ==================== 范围操作 ====================
    
    /**
     * 获取一天的开始时间 (00:00:00)
     */
    public static LocalDateTime startOfDay(LocalDate date) {
        return date == null ? null : date.atStartOfDay();
    }
    
    /**
     * 获取一天的结束时间 (23:59:59)
     */
    public static LocalDateTime endOfDay(LocalDate date) {
        return date == null ? null : date.atTime(LocalTime.MAX);
    }
    
    /**
     * 获取本月第一天
     */
    public static LocalDate firstDayOfMonth(LocalDate date) {
        return date == null ? null : date.withDayOfMonth(1);
    }
    
    /**
     * 获取本月最后一天
     */
    public static LocalDate lastDayOfMonth(LocalDate date) {
        return date == null ? null : date.withDayOfMonth(date.lengthOfMonth());
    }
    
    /**
     * 获取本年第一天
     */
    public static LocalDate firstDayOfYear(LocalDate date) {
        return date == null ? null : date.withDayOfYear(1);
    }
    
    /**
     * 获取本年最后一天
     */
    public static LocalDate lastDayOfYear(LocalDate date) {
        return date == null ? null : date.withDayOfYear(date.lengthOfYear());
    }
}
